package mx.edu.itesm.tps.proyecto.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import javax.sql.DataSource;
import mx.edu.itesm.tps.proyecto.pojo.Exam;
import mx.edu.itesm.tps.proyecto.pojo.ExamenReactivo;
import mx.edu.itesm.tps.proyecto.pojo.Pregunta;
import mx.edu.itesm.tps.proyecto.pojo.Resultado;
import mx.edu.itesm.tps.proyecto.pojo.UserExam;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.webflow.action.FormAction;

public class ExamDao extends FormAction implements ProjectEventDao {

    private SimpleJdbcTemplate simpleJdbcTemplate;
    private SimpleJdbcInsert insertExam;
    private SimpleJdbcInsert insertResultado;
    private SimpleJdbcInsert insertGrade;
    private SimpleJdbcInsert insertExamen;
    private SimpleJdbcInsert insertExamenReactivo;

    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
        this.insertExam = new SimpleJdbcInsert(dataSource).withTableName("exams");
        this.insertResultado = new SimpleJdbcInsert(dataSource).withTableName("resultado");
        this.insertGrade = new SimpleJdbcInsert(dataSource).withTableName("user_exam");
        this.insertExamen = new SimpleJdbcInsert(dataSource).withTableName("exams");
        this.insertExamenReactivo = new SimpleJdbcInsert(dataSource).withTableName("exam_reactivo");
    }

    public List getExams() {
        return simpleJdbcTemplate.queryForList("SELECT id, name FROM exams", new Object[]{});
    }

    public List getExams(String course) {
        return simpleJdbcTemplate.queryForList("SELECT * FROM exams WHERE course = ?", new Object[]{course});
    }

    public Exam getExamById(Integer id) {
        return getById(id.intValue());
    }

    public int getUltExamen() {
        int exId = simpleJdbcTemplate.queryForInt("SELECT id FROM exams ORDER BY id DESC LIMIT 1 ", new Object[]{});
        return exId;
    }

    public List<Resultado> getResultadosExamenAlumno(String exId, String alId) {
        return simpleJdbcTemplate.query("SELECT * FROM resultado WHERE examId = ? AND alumnoId = ?", new ResultadoMapper(), new Object[]{exId, alId});
    }

    public Pregunta getRespuestaCorrectaById(String respId) {
        return simpleJdbcTemplate.queryForObject("SELECT respuesta FROM respuesta WHERE reactivo = ? AND correcto = 'Si' LIMIT 1", new PreguntaRespMapper(), new Object[]{respId});
    }

    private int calificaExamen(String exId, String alId) {
        int totalPreguntas = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) AS total FROM exam_reactivo WHERE exam_id = ?", new Object[]{exId});
        int totalCorrectas = 0;

        List<Resultado> respuestas = getResultadosExamenAlumno(exId, alId);

        for (Iterator<Resultado> iterResp = respuestas.iterator(); iterResp.hasNext();) {
            Resultado res = iterResp.next();

            System.out.println("Checando res: " + res.getPreguntaId() + ":" + res.getRespuesta());

            Pregunta preg = getRespuestaCorrectaById(res.getPreguntaId());

            System.out.println("Resp correcta: " + preg.getCorrecta() + "(inp: " + res.getRespuesta() + ")");

            if (preg.getCorrecta().equalsIgnoreCase(res.getRespuesta())) {
                totalCorrectas++;
            }
        }

        int calif = (int) ((totalCorrectas / totalPreguntas) * 100);

        UserExam ue = new UserExam();
        ue.setUser(alId);
        ue.setExamid(Integer.parseInt(exId));
        ue.setGrade(calif);

        addGrade(ue);

        return calif;
    }

    private Exam getById(int id) {
        return simpleJdbcTemplate.queryForObject("SELECT id, name FROM exams WHERE id = ?", new ExamMapper(), id);
    }

    public List<Pregunta> getPreguntasExamen(String id) {
        return simpleJdbcTemplate.query("SELECT r.reactivo, r.tipo, r.id, GROUP_CONCAT(DISTINCT res.respuesta ORDER BY res.id SEPARATOR '|') AS respuestas, GROUP_CONCAT( DISTINCT res.respuesta ORDER BY correcto DESC SEPARATOR '|' ) AS correcta FROM reactivo AS r, respuesta AS res WHERE r.id IN (SELECT reactivo_id FROM exam_reactivo WHERE exam_id = ?) AND res.reactivo = r.id GROUP BY r.id", new PreguntaMapper(), new Object[]{id});
    }

    public List<Pregunta> getExamenMock(String id, String lim) {
        String limite = "LIMIT " + lim;
        String query = "SELECT rec.id AS id, GROUP_CONCAT(DISTINCT res.respuesta ORDER BY RAND() SEPARATOR '|') AS respuestas, GROUP_CONCAT(DISTINCT res.respuesta ORDER BY correcto DESC SEPARATOR '|') AS correcta, rec.reactivo, rec.tipo FROM respuesta AS res, reactivo AS rec, learning AS l, subtema AS s, tema AS t, courses AS c WHERE res.reactivo = rec.id AND rec.learning = l.id AND l.subtema = s.id AND s.tema = t.id AND t.curso = c.id AND c.id = ? GROUP BY rec.reactivo ORDER BY reactivo ASC ";
        String queryF = query + limite;
        System.out.println(queryF);

        String exa = "Examen Mock";

        Exam ex = new Exam();
        ex.setCourse(id);
        ex.setName(exa);
        addExamen(ex);

        int exId = simpleJdbcTemplate.queryForInt("SELECT id FROM exams ORDER BY id DESC LIMIT 1 ", new Object[]{});
        List<Pregunta> examen = simpleJdbcTemplate.query(queryF, new PreguntaMapper(), new Object[]{id});

        ArrayList<Pregunta> output = new ArrayList<Pregunta>();
        int limit = Integer.parseInt(lim);
        int i = 0;

        for (Iterator<Pregunta> iter = examen.iterator(); iter.hasNext();) {
            if (i++ >= limit) {
                break;
            }
            Pregunta p = iter.next();
            System.out.println(p.getId());

            ExamenReactivo eR = new ExamenReactivo();
            eR.setReactivoId(p.getId() + "");
            eR.setExamId(exId + "");

            addExamenReac(eR);
        }

        return simpleJdbcTemplate.query(queryF, new PreguntaMapper(), new Object[]{id});
    }

    public boolean puedeResponder(String exId, String alId) {
        if (exId == null && alId == null) {
            return false;
        }

        int total = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) AS total FROM resultado WHERE examId = ? AND alumnoId = ? LIMIT 1", new Object[]{exId, alId});


        return (total == 0);
    }

    public void addGrade(UserExam user) {
        Map<String, Object> parameters = new HashMap<String, Object>(UserExam.class.getDeclaredFields().length);
        parameters.put("user", user.getUser());
        parameters.put("examid", user.getExamid());
        parameters.put("grade", user.getGrade());

        insertGrade.execute(parameters);
    }

    public int addResultados(String exId, String alId, String mul, String vf, String rel, String abi) {
        System.out.println("Ex" + exId);
        System.out.println("Al" + alId);
        System.out.println("Mul" + mul);
        System.out.println("Vf" + vf);
        System.out.println("Rel" + rel);
        System.out.println("Abi" + abi);

        if (exId == null || alId == null) {
            return -1;
        }

        if (mul == null && vf == null && rel == null && abi == null) {
            return -1;
        }

        String[] multiple = mul.split("\\|");
        String[] vyf = vf.split("\\|");
        String[] relacionar = rel.split("\\|");
        String[] abierta = abi.split("\\|");

        for (int i = 0; i < multiple.length; i++) {

            if (multiple[i] != null) {
                String[] info = multiple[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                System.out.println("Info " + info[0] + ":" + info[1]);
                addResultado(res);
            }
        }

        for (int i = 0; i < vyf.length; i++) {
            if (vyf[i] != null) {
                String[] info = vyf[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        for (int i = 0; i < relacionar.length; i++) {
            if (relacionar[i] != null) {
                String[] info = relacionar[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        for (int i = 0; i < abierta.length; i++) {
            if (abierta[i] != null) {
                String[] info = abierta[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        return calificaExamen(exId, alId);
    }

    public int addResultadosM(String exId, String alId, String mul, String vf, String rel, String abi) {
        System.out.println("Ex" + exId);
        System.out.println("Al" + alId);
        System.out.println("Mul" + mul);
        System.out.println("Vf" + vf);
        System.out.println("Rel" + rel);
        System.out.println("Abi" + abi);

        if (exId == null || alId == null) {
            return -1;
        }

        if (mul == null && vf == null && rel == null && abi == null) {
            return -1;
        }

        String[] multiple = mul.split("\\|");
        String[] vyf = vf.split("\\|");
        String[] relacionar = rel.split("\\|");
        String[] abierta = abi.split("\\|");

        for (int i = 0; i < multiple.length; i++) {

            if (multiple[i] != null) {
                String[] info = multiple[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                System.out.println("Info " + info[0] + ":" + info[1]);
                addResultado(res);
            }
        }

        for (int i = 0; i < vyf.length; i++) {
            if (vyf[i] != null) {
                String[] info = vyf[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        for (int i = 0; i < relacionar.length; i++) {
            if (relacionar[i] != null) {
                String[] info = relacionar[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        for (int i = 0; i < abierta.length; i++) {
            if (abierta[i] != null) {
                String[] info = abierta[i].split("\\-");

                if (info.length != 2) {
                    continue;
                }

                String preg = info[0];
                String resp = info[1];

                if (info.length != 2) {
                    continue;
                }

                Resultado res = new Resultado();
                res.setExamId(exId);
                res.setAlumnoId(alId);
                res.setRespuesta(resp);
                res.setPreguntaId(preg);

                addResultado(res);
            }
        }

        return calificaExamen(exId, alId);
    }

    public void add(Exam exam) {
        Map<String, Object> parameters = new HashMap<String, Object>(Exam.class.getDeclaredFields().length);
        parameters.put("id", exam.getId());
        parameters.put("name", exam.getName());

        insertExam.execute(parameters);
    }

    public void addExamen(Exam ex) {
        Map<String, Object> parameters = new HashMap<String, Object>(Exam.class.getDeclaredFields().length);
        parameters.put("name", ex.getName());
        parameters.put("course", ex.getCourse());

        insertExamen.execute(parameters);
    }

    public void addExamenReac(ExamenReactivo eR) {
        Map<String, Object> parameters = new HashMap<String, Object>(ExamenReactivo.class.getDeclaredFields().length);
        parameters.put("reactivo_id", eR.getReactivoId());
        parameters.put("exam_id", eR.getExamId());

        insertExamenReactivo.execute(parameters);
    }

    public void addResultado(Resultado res) {
        Map<String, Object> parameters = new HashMap<String, Object>(Resultado.class.getDeclaredFields().length);
        parameters.put("examId", res.getExamId());
        parameters.put("alumnoId", res.getAlumnoId());
        parameters.put("respuesta", res.getRespuesta());
        parameters.put("preguntaId", res.getPreguntaId());

        insertResultado.execute(parameters);
    }

    private class ExamMapper implements ParameterizedRowMapper<Exam> {

        public Exam mapRow(ResultSet rs, int rowNum) throws SQLException {
            Exam exam = new Exam();
            exam.setId(rs.getInt("id"));
            exam.setName(rs.getString("name"));
            return exam;
        }
    }

    private class ResultadoMapper implements ParameterizedRowMapper<Resultado> {

        public Resultado mapRow(ResultSet rs, int rowNum) throws SQLException {
            Resultado res = new Resultado();
            res.setExamId(rs.getString("examId"));
            res.setAlumnoId(rs.getString("alumnoId"));
            res.setRespuesta(rs.getString("respuesta"));
            res.setPreguntaId(rs.getString("preguntaId"));
            return res;
        }
    }

    private class PreguntaMapper implements ParameterizedRowMapper<Pregunta> {

        public Pregunta mapRow(ResultSet rs, int rowNum) throws SQLException {
            Pregunta p = new Pregunta();

            String[] respuestas = rs.getString("respuestas").split("\\|");
            String correcta = rs.getString("correcta").split("\\|")[0];
            String pregunta = rs.getString("reactivo");
            int tipo = rs.getInt("tipo");
            int id = rs.getInt("id");

            for (int i = 0; i < respuestas.length; i++) {
                p.getRespuestas().add(respuestas[i]);
            }

            p.setCorrecta(correcta);
            p.setPregunta(pregunta);
            p.setTipo(tipo);
            p.setId(id);

            return p;
        }
    }

    private class PreguntaRespMapper implements ParameterizedRowMapper<Pregunta> {

        public Pregunta mapRow(ResultSet rs, int rowNum) throws SQLException {
            Pregunta p = new Pregunta();

            p.setCorrecta(rs.getString("respuesta"));

            return p;
        }
    }
}
